import java.util.ArrayList;

/**
 * 
 * @author Devin Wolanick
 * @Version 1.0
 * 
 * Dealer is a player and/or Dealer
 */
public class Dealer implements BlackJackPlayer{
	
	/**
	 * Variables
	 */
	private Watcher myWatcher;
	private ArrayList<BlackJackPlayer> playerList = new ArrayList<BlackJackPlayer>();
	private ArrayList<Card> dealerHand = new ArrayList<Card>();
	private int numDecks;
	private int currentPlayer = 0;
	private int shoeThresh = 20; //Percent
	private CardStack myDeck;
	private DebugWindow myDebug;
	private int hitType;
	
	/**
	 * Constructor
	 * @param numDecks Number of Decks
	 * @param playerList List of Players
	 */
	public Dealer(int numDecks, int hitType, ArrayList<BlackJackPlayer> playerList, Watcher myWatcher, DebugWindow myDebug) {
		this.myWatcher = myWatcher;
		this.hitType = hitType;
		this.myDebug = myDebug;
		this.playerList = playerList;
		this.numDecks = numDecks;
		myDeck = new Shoe(numDecks);
		myDeck.shuffle();
	}
	
	/**
	 * Dealer draws a card
	 * @return Dealt Card
	 */
	private Card drawCard() {
		Card aCard = myDeck.drawCard();
		myDebug.addOne("Card Drawn: "+ aCard.display());
		return aCard;
	}
	
	/**
	 * Kills tops Card
	 */
	private void killCard() {
		myDebug.addOne("Card Killed");
		myDeck.killCard();
	}
	
	/**
	 * Creates a new Deck
	 */
	private void newDeck() {
		myDebug.addTwo("New Deck Made");
		myDeck = new Shoe(numDecks);
	}
	
	public void setThresh(int thresh) {
		shoeThresh = thresh;
	}

	/**
	 * Evaluates Dealers hand
	 * @return List of possible values
	 */
	public ArrayList<Integer> evaluateHand(){
		myDebug.addTwo("Evaluating Dealers Hand");
		EvaluateHand evaluator = new EvaluateHand(dealerHand);
		return evaluator.evaluate();
	}
	
	/**
	 * Deals the initial Round of cards
	 */
	public void initialDeal() {
		myDebug.addTwo("Dealing Table");
		Card aCard = null;
		for (int i=0; i<playerList.size(); i++) {
			aCard = drawCard();
			myWatcher.takeCard(aCard);
			playerList.get(i).receiveCard(aCard);
			myDebug.addThree("Player "+(i+1)+" Recives: "+ aCard.display());
		}
		aCard = drawCard();
		receiveCard(aCard);
		myDebug.addTwo("Dealer Recives: "+ aCard.display());
		myWatcher.takeCard(aCard);
		for (int i=0; i<playerList.size(); i++) {
			aCard = drawCard();
			myWatcher.takeCard(aCard);
			playerList.get(i).receiveCard(aCard);
			myDebug.addThree("Player "+(i+1)+" Recives: "+ aCard.display());
		}
//		aCard = drawCard();
//		myDebug.addTwo("Dealer Receives: "+ aCard.display());
//		myWatcher.takeCard(aCard);
//		receiveCard(aCard);
	}
	
	/**
	 * Handles a players actions                NOT BEING USED!
	 */
/*	public void handlePlayer(BlackJackPlayer myPlayer) {
		ArrayList<Card> faceUpCard = new ArrayList<Card>();
		faceUpCard.add(dealerHand.get(0));
		EvaluateHand faceUpEvaluate = new EvaluateHand(faceUpCard);
		int playerDecision = myPlayer.requestAction(faceUpEvaluate.evaluate());
		if (playerDecision == 2 || playerDecision == 3)
			return;
		else if (playerDecision == 1) {
			myPlayer.receiveCard(drawCard());             //Report
			handlePlayer(myPlayer);
		}
	}*/
	
	/**
	 * Hits current Player
	 */
	public int hitPlayer() {
		Card aCard = drawCard();
		myWatcher.takeCard(aCard);
		myDebug.addThree("Player "+(currentPlayer+1)+" hits: "+aCard.display());
		playerList.get(currentPlayer).receiveCard(aCard);
		if (playerList.get(currentPlayer).busted())
			return 1;
		else
			return 0;		
	}
	
	/**
	 * Stands current Player
	 */
	public int standPlayer() {
		myDebug.addThree("Player (Force?)Stands");
		if (currentPlayer==playerList.size()-1) {
			handleSelf();
			currentPlayer = 0;
			return 1;
		}
		else {
			currentPlayer++;
			return 0;
		}	
	}
	
	/**
	 * Handles dealers Actions (S17: Stand 17)
	 */
	private void handleSelf() {
		myDebug.addTwo("Dealer Takes Action");
		//Take Second Card
		Card aCard = drawCard();
		myDebug.addTwo("Dealer Receives: "+ aCard.display());
		myWatcher.takeCard(aCard);
		receiveCard(aCard);
		while (true) {
			ArrayList<Integer> dealerValues = evaluateHand();
			
			//Remove Busts
			for (int i=0; i<dealerValues.size(); i++)
				if (dealerValues.get(i)>21) {
					myDebug.addTwo("Dealer Removes Busts");
					dealerValues.remove(i);
					i=0;
				}
			//Bust
			if (dealerValues.isEmpty()) {
				myDebug.addTwo("Dealer BUSTED");
				return;
			}
			//Get largest number
			int largestNum = 0;
			for (int i=0; i<dealerValues.size(); i++)
				if (dealerValues.get(i)>largestNum)
					largestNum = dealerValues.get(i);
			//Greater than 17
			if (largestNum>17)
				return;
			else if (largestNum == 17) {
				if (hitType == 0) {
					myDebug.addTwo("Dealer S17");
					return;
				}
				else {
					boolean isSoft = false;
					for (int i=0; i<dealerValues.size(); i++)
						if (dealerValues.get(i) == 7) {
							myDebug.addTwo("Dealers Hits Soft 17");
							isSoft = true;
						}
					if (isSoft == false)
						return;
				}
			}
//			else {
			    aCard = drawCard();
				myWatcher.takeCard(aCard);
				myDebug.addTwo("Dealer hit: "+aCard.display());
				receiveCard(aCard);
//			}
		}
	}
	
	/**
	 * Replaces a nearly empty shoe
	 */
	private void checkShoe() {
		myDebug.addTwo("Check Shoe");
		if (myDeck.getSize()/(numDecks*52.0)*100.0<shoeThresh || myDeck.getSize()<40) {
			myDebug.addTwo("Making new Deck: "+ (myDeck.getSize()/(numDecks*52.0)*100.0));
			newDeck();
			myDeck.shuffle();
			killCard();
			myWatcher.resetAll();
		}
	} 
	
	/**
	 * Initiates Round
	 */
	public void dealTable() {
		checkShoe();
		initialDeal();
	}

	/**
	 * Displays Dealers Hand                 NOT BEING USED!
	 */
/*	private void displayHand() {
		System.out.print("Dealer Holds: ");
		for (int i=0; i<dealerHand.size(); i++) {
			int cardNum  = dealerHand.get(i).getNumber();
			int cardSuit = dealerHand.get(i).getSuit();
			System.out.print(cardNumbers[cardNum-1]+" of "+cardSuits[cardSuit-1]+ "   ");
		}
		System.out.println();
	}*/

	/**
	 * Displays Dealers Hand Value           NOT BEING USED!
	 */
/*	private void displayValue() {
		System.out.println("Dealers Hand Value(s): "+ evaluateHand().toString());
	}*/

	/**
	 * Returns a List of Players Hands
	 * @return List of Lists of Cards
	 */
	public ArrayList<ArrayList<Card>> reportCards() {
		ArrayList<ArrayList<Card>> handsList = new ArrayList<ArrayList<Card>>();
		for (int i=0; i<playerList.size(); i++)
			handsList.add(playerList.get(i).getHand());
		handsList.add(getHand());
		return handsList;
	}
	
	/**
	 * Returns a List of Players Hand Values
	 * @return Hand Values : Array of Array<Integer>
	 */
	public ArrayList<ArrayList<Integer>> reportValues() {
		ArrayList<ArrayList<Integer>> valuesList = new ArrayList<ArrayList<Integer>>();
		for (int i=0; i<playerList.size(); i++)
			valuesList.add(playerList.get(i).evaluateHand());
		valuesList.add(evaluateHand());
		return valuesList;
	}
	
	/**
	 * Check if Dealer Busted             NOT BEING USED YET!
	 * @return True if Busted
	 */
	public boolean busted() {
		int maxValue = 22;
		ArrayList<Integer> possibleValues = evaluateHand();
		for (int i=0; i<possibleValues.size(); i++)
			if (possibleValues.get(i)<maxValue)
				maxValue = possibleValues.get(i);
		if (maxValue>21) {
			myDebug.addTwo("BUSTED");
			return true;
		}
		return false;
	}

	/**
	 * Discards Dealers Hand
	 */
	public void discardHand() {
		dealerHand.clear();
	}

	/**
	 * Returns Dealers Hand
	 * @return List of Cards
	 */
	@SuppressWarnings("unchecked")
	public ArrayList<Card> getHand() {
		return (ArrayList<Card>) dealerHand.clone();
	}

	/**
	 * Receive a Card
	 * @param someCard Card to receive
	 */
	public void receiveCard(Card someCard) {
		dealerHand.add(someCard);
	}
	
	/**
	 * Clears all cards from table
	 */
	public void clearTable() {
		for (int i=0; i<playerList.size(); i++)
			playerList.get(i).discardHand();
		discardHand();
	}
}